#include "app_device.h"
#include "app_common.h"
#include "app_mqtt.h"
#include "app_pool.h"
#include "app_buffer.h"
#include "app_message.h"
#include "log.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>

/**
 * 设备的初始化
 * 1  打开文件 产生文件描述符
 * 2  初始化设备结构体的各个属性
 */
Device *app_device_init(char *file_name)
{ // 1  打开文件 产生文件描述符
    int fd = open(file_name, O_RDWR, 0666);
    if (fd < 0)
    {
        perror("open file failed");
        return NULL;
    }
    // 2 初始化设备结构体的各个属性
    Device *device = (Device *)malloc(sizeof(Device));
    // 3 赋值
    device->file_name = file_name;
    device->fd = fd;
    device->conn_type = CONN_TYPE_NONE;
    device->dev_type = DEVICE_TYPE_NONE;
    device->read_buf = app_buffer_init(1024);
    device->write_buf = app_buffer_init(1024);
    device->post_read = NULL;
    device->pre_write = NULL;
    device->last_write_ts = 0;
    device->running = 0;
    device->write_interval_ms = 100;
    return device;
}

/**
 * 释放设备资源
 */
void app_device_free(Device *device)
{
    app_buffer_free(device->read_buf);
    app_buffer_free(device->write_buf);
    close(device->fd);
    free(device);
}

/**
 * 启动设备  进程的主线程 启动设备线程
 * @  1. 启动读取硬件设备的线程 调用app_device_read_dev_file
 * @return 0 成功 -1 失败
 */
int app_device_start(Device *device)
{
    log_info("app_device_start");
    if (device->running)
    {
        log_warn("device is running");
        return 0;
    }
    int ret = pthread_create(&device->read_thread, NULL, app_device_read_dev_file, device);
    if (ret < 0)
    {
        perror("create read thread failed");
        return -1;
    }
    device->running = 1;
    log_info("app_device_started!");
    return 0;
}

/**
 * 读取硬件设备文件的数据 (异步)   设备的读取线程
 * @param 实际上是Device 结构体指针
 *  1 持续读取设备文件内容
 *  2 写入读缓冲区
 *  3  向线程池提交任务 （发送数据的任务）调用app_device_send_mqtt
 */
void *app_device_read_dev_file(void *arg)
{
    Device *device = (Device *)arg;
    char temp_read_buff[100];
    while (1)
    { // 读取到临时缓冲区  //读取的是蓝牙格式的 数据
        int read_size = read(device->fd, temp_read_buff, 100);
        if (read_size > 0)
        {
            log_info("从设备中读取到数据:%d", read_size);

            // 预处理 实际上是把临时缓冲区的数据进行修改 同时read_size 也进行了修改
            if (device->post_read)
            {
                read_size = device->post_read(device, temp_read_buff, read_size);
            }
            // 经过预处理之后 数据从设备格式变为字节u数组 存储入缓冲区
            if (read_size > 0)
            {
                app_buffer_write(device->read_buf, temp_read_buff, read_size);
                // 接下来 需要利用线程池来处理数据的发送工作
                int ret = app_pool_submit_task(app_device_send_mqtt, device);
                if (ret < 0)
                {
                    perror("app_device_read_thread_func:app_pool_submit_task");
                }
            }
        }
    }
}

/**
 *  向消息队列中写入数据    线程池中的线程
 * @param 实际上是Device 结构体指针
 *   //1 从设备中读取数据 读取到一个 临时buff中
   //2 把字节数组转换为json
   //3 发送数据
 */
void *app_device_send_mqtt(void *arg)
{
    log_info("app_device_send_mqtt");
    Device *device = (Device *)arg;
    // 1 从设备中读取数据 读取到一个 临时buff中
    char tmp_buf[100];
    int read_size = app_buffer_read(device->read_buf, tmp_buf, 100);
    // 2 把字节数组转换为json
    Message *message = app_message_bytes_to_message(tmp_buf);
    char *json = app_message_message_to_json(message);
    // 3 发送数据
    app_mqtt_send(json, strlen(json));
    log_info("send mqtt message:%s", json);
}

/**
 * 从路由器接收数据
 *  1 写入数据(已经是字节数组)到写缓冲区
 *  2 提交任务给a线程池（任务： 将数据写入设备文件）
 */
int app_device_recv_router(Device *device, char *data, int len)
{
    app_buffer_write(device->write_buf, data, len);

    app_pool_submit_task(app_device_write_dev_file, device);

    return 0;
}

/**
 * 把设备写缓冲区的数据写入设备文件
 * @param 实际上是Device 结构体指针
 * 1 读取写缓冲区的数据
 * 2 将数据写入设备文件
 */
void *app_device_write_dev_file(void *arg)
{
    log_info("有数据需要写入文件");
    Device *device = (Device *)arg;
    char tmp_buff[100];
    int read_size = app_buffer_read(device->write_buf, tmp_buff, 100);
    if (read_size > 0)
    {
        log_info("write_dev_file read_size:%d", read_size);
        // 把字节数组 转换为 设备格式的数据
        if (device->pre_write)
        {
            read_size = device->pre_write(device, tmp_buff, read_size);
        }
        if (read_size > 0)
        {
            long long  cur_ms = app_common_get_curtime_ms();
            log_info("cur write ms :%lld", cur_ms);
            long interval_ms = cur_ms - device->last_write_ts;
            if (device->last_write_ts != 0 && interval_ms < device->write_interval_ms)
            {
                usleep((device->write_interval_ms - interval_ms) * 1000);
            }
            ssize_t write_size = write(device->fd, tmp_buff, read_size);
            log_info("成功写入文件 大小:%ld", write_size);
            device->last_write_ts = app_common_get_curtime_ms();
        }
    }
}
